##############################################################################
# client.py
#
# Handles client-side network connections.
##############################################################################

#FIXME - Remove dependency (import bgl)

import sys, socket

# The client allows a communication system with the server.
class Client(object):
    def __init__(self):
        self.socket = None
        self.buff = ""
        self.queue = ""
        self.msgs = {}
        
        self.push("txt","PyNTT - The Python Network Table-Top")
        self.push("txt","Copyright 2010 - Dmitri Amariei")
        self.push("txt","-" * 80)
        
    # Connect to the server. If we get disconnected, we can connect a second
    # time with the same client.
    def connect(self, address, port):
        self.socket = socket.socket()
        self.socket.settimeout( 10.0 )
        try:
            self.socket.connect( (address,port) )
        except:
            self.socket.close()
            self.socket = None
            return False
        self.socket.settimeout( 0.01 )
        return True
    
    # Put a message on the queue. It will be periodically fed to the server
    # one KB at a time.
    def send(self, msg):
        if self.socket == None: return
        
        length = str(len(msg))
        length = ("0"*(8-len(length)))+length
        self.queue += length+msg
    
    # Update the in and out queues.
    def update(self):
        if self.socket == None: return
        data = None
        
        if len(self.queue) > 0:
            try:
                self.socket.send( self.queue[:1024] )
                self.queue = self.queue[1024:]
            except socket.timeout: pass
            except: self.kill()
        
        try:
            data = self.socket.recv(1024)
            if data == "": self.kill()
        except socket.timeout: pass
        except socket.error: self.kill()
        
        if data == None: data = ""
        
        self.buff += data   
        if not self.buff[:8].isdigit():
            self.buff = ""
        if len(self.buff) >= 8:
            size = int(self.buff[:8])
            if len(self.buff[8:]) >= size:
                m = self.buff[8:size+8]
                if m[:3] not in self.msgs:
                    self.msgs[ m[:3] ] = []
                self.msgs[ m[:3] ].append( m[3:] )
                self.buff = self.buff[size+8:]
    
    # Get a indexed buffer from the client. Each widget has a 3-digit
    # control code to keep its messages from interfering with others.
    def get(self, code):
        if code not in self.msgs:
            self.msgs[code] = []
        report = self.msgs[code]
        self.msgs[code] = []
        return report
    
    # Fake a message from the server.
    def push(self, code, msg):
        if code not in self.msgs:
            self.msgs[code] = []
        self.msgs[code].append(msg)
    
    # Kill the connection locally.
    def kill(self):
        self.socket.close()
        self.socket = None
        self.push("txt","Remote connection has been closed.")
    
    # Find out if we still have a connection.
    def alive(self):
        return self.socket != None
